import sim
import checkNet
import log
import utime
from misc import Power
from umqtt import MQTTClient
import _thread
import ujson
from machine import UART
import quecgnss
import ure
 

log.basicConfig(level=log.NOTSET)   # 设置日志输出级别
CarLock_log = log.getLogger("Lock")

#-------------------网络检测部分-----------------------------------
def SIM_Init():
    r=sim.getStatus()
    if r==1:
        CarLock_log.info("SIM init OK")
       
    else:
        CarLock_log.error("SIM init failed:{}".format(r))
    return r

PROJECT_NAME = "QuecPython_lock"    
PROJECT_VERSION = "1.0.0"

def Net_Init():
    global checknet
    checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION)
    stagecode, subcode = checknet.wait_network_connected(30)
    if stagecode == 3 and subcode == 1:
        CarLock_log.info('Network connection successful!')
        return 1
    else:
        CarLock_log.error('Network connection failed! stagecode = {}, subcode = {}'.format(stagecode, subcode))
        return 0

def Internet_Init():
    r=SIM_Init()
    if r==1:
        if Net_Init():
            return 1  
        else:
            return 0
    else:
        return 0
#-----------------------------------------------------------------

#--------------------------MQTT部分-------------------------------

CLIENT_ID = '6804b3f19314d1185113e171_lock_0_0_0_2025042008'                    #客户端 
SERVER = 'db26cf2b1f.st1.iotda-device.cn-north-4.myhuaweicloud.com'             #服务器地址
PORT = 1883
USER_NAME = '6804b3f19314d1185113e171_lock_0'
PASSWORD = '7b05d72adf4874e28d5fd773076d77cf22dfb47dfd7286aa78d48d62ff1d37a9'

lock_unidle_data={
    "services": [{
            "service_id": "lock",
            "properties": {
                "lock_state": "True"
            }
	}]
}

lock_idle_data={
    "services": [{
            "service_id": "lock",
            "properties": {
                "lock_state": "False"
            }
	}]
}

lock_idle_msg = ujson.dumps(lock_idle_data)         #地锁空闲消息 
lock_unidle_msg = ujson.dumps(lock_unidle_data)     #地锁不空闲消息

should_write_lock_state = lock_idle_msg             #初始化应发送地锁的状态为空闲

def MQTT_init():
    global mqtt_obj

    mqtt_obj = MQTTClient(
            client_id=CLIENT_ID,
            server=SERVER,
            port=PORT,
            user=USER_NAME,
            password=PASSWORD,
            keepalive=30)
    mqtt_obj.set_callback(sub_cb)
    try:
        mqtt_obj.connect()
        CarLock_log.info('Successfully connected to Huawei Cloud IoT platform')
        mqtt_obj.subscribe('$oc/devices/{}/sys/commands/#'.format(USER_NAME))
        mqtt_obj.subscribe('$oc/devices/6804b3f19314d1185113e171_lock_0/sys/messages/down')
        CarLock_log.info('Successfully subscribe')
        mqtt_obj.publish('$oc/devices/{}/sys/properties/report'.format(USER_NAME),lock_idle_msg)
        uart2.write("LockIdle\r\n")
    except Exception as e:
        CarLock_log.error('failed connected to Huawei Cloud IoT platform,Error:{}'.format(e))


def sub_cb(topic, msg):     #mqtt消息回调函数
    global should_write_lock_state
    CarLock_log.info("Subscribe Recv: Topic={}, Msg={}".format(topic.decode(), msg.decode()))
    try:
        # 解析消息内容
        msg_dict = ujson.loads(msg.decode())
        content = msg_dict.get("content", {})
        
        # 检查是否存在 "lock" 字段
        if "lock" in content:
            lock_value = content["lock"]
            CarLock_log.info("Extracted lock field: lock={}".format(lock_value))
            # 根据 lock 的值更新地锁状态
            if lock_value == 0:
                # should_write_lock_state = lock_idle_msg  # 发送空闲状态
                uart2_data = "unlock"
                uart2_msg = add_frame(uart2_data)
                uart2.write(uart2_msg)
            elif lock_value == 1:
                # should_write_lock_state = lock_unidle_msg  # 发送占用状态
                uart2_data = "lock"
                uart2_msg = add_frame(uart2_data)
                uart2.write(uart2_msg)

        # 检查是否存在 "num" 字段（车牌号）
        elif "num" in content:
            num_value = content["num"]
            CarLock_log.info("Extracted num field: num={}".format(num_value))
            uart2_data = num_value.decode().strip()     # 解码并去除首尾空白字符及换行符
            uart2_msg = add_frame(uart2_data)
            uart2.write(uart2_msg)
            
    except Exception as e:
        CarLock_log.error("Failed to parse message: {}".format(e))

    #回复云平台下发的命令
    topic = topic.decode()
    if r'/sys/commands/request_id=' in topic:
        publishtopic = '$oc/devices/{}/sys/commands/response/request_id='.format(USER_NAME)
        publishtopic += topic.split("=")[-1]
        response_msg = b'''{"result_code": 0}'''
        mqtt_obj.publish(publishtopic, response_msg)
    
#-----------------------------------------------------------------

#-------------------------GNSS定位部分-----------------------------
 
def convert_latitude(lat_str):
    """将ddmm.mmmm格式的纬度字符串转换为十进制度数"""
    degrees = int(lat_str[:2])
    minutes = float(lat_str[2:])
    return degrees + minutes / 60

def convert_longitude(lon_str):
    """将dddmm.mmmm格式的经度字符串转换为十进制度数"""
    degrees = int(lon_str[:3])
    minutes = float(lon_str[3:])
    return degrees + minutes / 60

def GNSS_Read():
    data = quecgnss.read(1024)
    data_gnss = data[1].decode()
    if len(data_gnss)==0:
        print("None Data")
    else:
        print("Get Data")
        #print(data_gnss)
        data1 = ure.search("GNRMC(.+?)M", data_gnss)
        deta2 = ure.search("GPGSV(.+?)M", data_gnss)
        deta3 = ure.search("BDGSV(.+?)M", data_gnss)
        data4 = ure.search("GNGGA(.+?)M", data_gnss)
        try:
            if data1.group(0).split(",")[2] == 'A': 
                print("Available Data")           
                li=[data4.group(0).split(",")[2],data4.group(0).split(",")[3],data4.group(0).split(",")[4],data4.group(0).split(",")[5]]

                time_gnss = float(str(data4.group(0).split(",")[1]))        #时间戳                         
                # latitude = convert_latitude(str(li[0]))                     #纬度
                # longitude = convert_longitude(str(li[2]))                   #经度

                latitude = convert_latitude(li[0]) - 0.004961034 + 0.0009009009 + 0.0009009009#纬度
                longitude = convert_longitude(li[2]) + 0.0029175333 + 0.0018018018 + 0.00045045045#经度
                latitude_dir = str(data4.group(0).split(",")[3])            #纬度方向
                longitude_dir = str(data4.group(0).split(",")[5])           #经度时间
                gnss_data = {
                "services": [{
                        "service_id": "gnss_data",
                        "properties": {
                            "longitude":longitude,
				            "longitude_dir":longitude_dir,
                            "latitude":latitude,
				            "latitude_dir":latitude_dir,
                            "time_gnss":time_gnss
                        }
                }]
            }
                gnss_msg = ujson.dumps(gnss_data)
                mqtt_obj.publish('$oc/devices/{}/sys/properties/report'.format(USER_NAME),gnss_msg)
                print(time_gnss,latitude,latitude_dir,longitude,longitude_dir)
                lat0=int(int(float(li[0]))/100)
                lat1=int(int(float(li[0]))%100)
                lat2=int(li[0].split(".")[1])
                lon0=int(int(float(li[2]))/100)
                lon1=int(int(float(li[2]))%100)
                lon2=int(li[2].split(".")[1])
                lat_d=str(lat0)
                lat_m=str(lat1)+"."+str(lat2)
                lon_d=str(lon0)
                lon_m=str(lon1)+"."+str(lon2)

                return lat_d,lat_m,li[1],lon_d,lon_m,li[3]
        except:
            pass

def GNSS_Init():
    ret = quecgnss.init()
    if ret == 0:
        print('GNSS init ok.')
    else:
        print('GNSS init failed.')
        return -1
    ret = quecgnss.get_state()
    if ret == 2:
        print("Fetching data...")
#-----------------------------------------------------------------

#--------------------------UART部分-------------------------------
#uart2初始化
def UART_init():
    global uart2
    uart2 = UART(UART.UART2, 115200, 8, 0, 1, 0)
    uart2.set_callback(uart_call)                   

#串口接收回调函数
def uart_call(args):
    global should_write_lock_state
    msg = uart2.read(args[2])       # 读取串口数据
    if not msg:                     # 检查是否为空数据
        return
    
    try:
        # 检查帧头帧尾
        if msg[0] != 0xAA or msg[-1] != 0xFF:
            CarLock_log.warning("Invalid frame format")
            return

        # 提取有效载荷（排除头尾）
        payload = msg[1:-1]
        
        # 尝试解码有效载荷
        decoded_msg = payload.decode().strip().lower()
        # CarLock_log.info("UART received valid payload: %s", decoded_msg)

        if decoded_msg == "idle":
            should_write_lock_state = lock_idle_msg
            # CarLock_log.debug("Set lock state to IDLE{}".format(lock_idle_msg))
        elif decoded_msg == "unidle":
            should_write_lock_state = lock_unidle_msg
            # CarLock_log.debug("Set lock state to UNIDLE{}".format(lock_idle_msg))
        else:
            CarLock_log.warning("Unknown UART command: %s", decoded_msg)
            
    except UnicodeDecodeError:
            CarLock_log.error("Undefined binary command: %s", payload)
    except Exception as e:
        CarLock_log.error("UART processing error: %s", e)

#添加包头0xaa 包尾0xff
def add_frame(data):
    frame_head = b'\xaa'
    frame_tail = b'\xff'
    data_bytes = data.encode()  # 使用UTF-8编码
    return frame_head + data_bytes + frame_tail
#-----------------------------------------------------------------

#--------------------------线程部分-------------------------------
def wait_msg():
    while True:
        if mqtt_obj is not None:
            CarLock_log.info('wait_msg')
            mqtt_obj.wait_msg()
            utime.sleep(1)

def mqtt_wait():
    # 创建一个线程来监听接收MQTT消息
    _thread.stack_size(16 * 1024)
    _thread.start_new_thread(wait_msg, ())
#-----------------------------------------------------------------
def main():
    utime.sleep(5)
    Internet_Init()
    try:
        checknet.wait_network_connected()
    except BaseException as e:
        CarLock_log.critical("Network connection failed! Restarting... Error: {}".format(e))
        utime.sleep_ms(200)
        Power.powerRestart()
    checknet.poweron_print_once()

    UART_init()         #串口2初始化
    MQTT_init()         #MQTT连接初始化
    mqtt_wait()         #MQTT等待数据线程
    GNSS_Init()         #GNSS定位初始化
    last_gnss_time = 0
    last_pub_time = 0
    gnss_interval = 5   # GNSS数据上报间隔（秒）
    pub_interval = 5    # 状态上报间隔（秒）
    while True:
        try:
            #定时上报地锁状态
            current_time = utime.time()
            if current_time - last_pub_time >= pub_interval:
                mqtt_obj.publish('$oc/devices/{}/sys/properties/report'.format(USER_NAME), should_write_lock_state)
                last_pub_time = current_time
                CarLock_log.debug("Regular status report sent")
                
            #GNSS数据采集和上报
            if current_time - last_gnss_time >= gnss_interval:
                result = GNSS_Read()
                if result:
                    CarLock_log.info("GNSS data: {}".format(result))
                last_gnss_time = current_time
                
            utime.sleep_ms(100)
        except Exception as e:
            CarLock_log.error("Main loop error: {}".format(e))
            # 添加异常恢复逻辑
            try:
                mqtt_obj.disconnect()
            except:
                pass
            MQTT_init()  # 尝试重新初始化MQTT
            utime.sleep(5)
    
if __name__ == '__main__':
    main()
